#include "ApplyOpDialog.h"
#include "ui_ApplyOpDialog.h"

#include <QStandardItemModel>

ApplyOpDialog::ApplyOpDialog(QWidget *parent, const ImageWindow *from) :
    QDialog(parent),
    ui(new Ui::ApplyOpDialog)
{
    ui->setupUi(this);
    init(from);
}

ApplyOpDialog::~ApplyOpDialog()
{
    delete ui;
}

void ApplyOpDialog::init(const ImageWindow *from){
    initInfo(from);
    if(from->isStandard()) ui->radioButtonRound->setEnabled(false);

    ui->groupBoxRound->setEnabled(false);
    ui->groupBoxClipping->setEnabled(false);
    ui->groupBoxStretch->setEnabled(false);

     //We connect the radio button of the stretch operation
    QObject::connect(ui->radioButtonDefault,SIGNAL(toggled(bool)),this,SLOT(ManageButton()));
    QObject::connect(ui->radioButtonLinear,SIGNAL(toggled(bool)),this,SLOT(ManageButton()));
    QObject::connect(ui->radioButtonFree,SIGNAL(toggled(bool)),this,SLOT(ManageButton()));

    //We init according to the type of the image
    if(from->isStandard()){
        int min = std::numeric_limits<int>::min();
        int max = std::numeric_limits<int>::max();
        ui->spinBoxCutDown->setRange(min,max);
        ui->spinBoxCutDown->setRange(min,max);
        ui->doubleSpinBoxBefCenter->setRange(min,max);
        ui->doubleSpinBoxLow->setRange(min,max);
        ui->doubleSpinBoxCenter->setRange(min,max);
        ui->doubleSpinBoxUp->setRange(min,max);
    }else if(from->isDouble()){
        double min = std::numeric_limits<double>::min();
        double max = std::numeric_limits<double>::max();
        ui->spinBoxCutDown->setRange(min,max);
        ui->spinBoxCutDown->setRange(min,max);
        ui->doubleSpinBoxBefCenter->setRange(min,max);
        ui->doubleSpinBoxLow->setRange(min,max);
        ui->doubleSpinBoxCenter->setRange(min,max);
        ui->doubleSpinBoxUp->setRange(min,max);
    }

    //we vonnect all the spinboxes
    QObject::connect(ui->spinBoxCutDown,SIGNAL(valueChanged(double)),this,SLOT(CheckCut()));
    QObject::connect(ui->spinBoxCutUp,SIGNAL(valueChanged(double)),this,SLOT(CheckCut()));

    QObject::connect(ui->doubleSpinBoxBefCenter,SIGNAL(valueChanged(double)),this,SLOT(CheckStretch()));
    QObject::connect(ui->doubleSpinBoxLow,SIGNAL(valueChanged(double)),this,SLOT(CheckStretch()));
    QObject::connect(ui->doubleSpinBoxCenter,SIGNAL(valueChanged(double)),this,SLOT(CheckStretch()));
    QObject::connect(ui->doubleSpinBoxUp,SIGNAL(valueChanged(double)),this,SLOT(CheckStretch()));

    //we initialize the value for te default case
    ui->doubleSpinBoxLow->setValue(0.);
    ui->doubleSpinBoxUp->setValue(255.);
    ui->doubleSpinBoxCenter->setValue(127.5);
    getBefCenter();

}

void ApplyOpDialog::initInfo(const ImageWindow *from){
    QStandardItemModel *model = new QStandardItemModel(4,3,this);
    model->setHorizontalHeaderItem(this->RED, new QStandardItem(QString(tr("Red"))));
    model->setHorizontalHeaderItem(this->GREEN, new QStandardItem(QString(tr("Green"))));
    model->setHorizontalHeaderItem(this->BLUE, new QStandardItem(QString(tr("Blue"))));
    model->setVerticalHeaderItem(this->MIN, new QStandardItem(QString(tr("Min"))));
    model->setVerticalHeaderItem(this->MEAN, new QStandardItem(QString(tr("Mean"))));
    model->setVerticalHeaderItem(this->MAX, new QStandardItem(QString(tr("max"))));
    model->setVerticalHeaderItem(this->STDDEV, new QStandardItem(QString(tr("Std. Dev."))));


    double maxtemp=0.;
    double mintemp=0.;
    if(from->isStandard()){
        const StandardImageWindow * siw = dynamic_cast<const StandardImageWindow*>(from);
        const Image_t<int> *image = siw->getImage();
        for(int k=0;k<image->getNbChannels();k++){
            int min; min = image->min(k); mintemp = std::min((int)mintemp,min);
            model->setItem(this->MIN,k,new QStandardItem(QString("%1").arg(image->min(k))));
            model->setItem(this->MEAN,k,new QStandardItem(QString("%1").arg(image->mean(k))));
            int max; max = image->max(k); maxtemp = std::max((int)maxtemp,max);
            model->setItem(this->MAX,k,new QStandardItem(QString("%1").arg(max)));
            model->setItem(this->STDDEV,k,new QStandardItem(QString("%1").arg(image->deviation((unsigned int)(k)))));
        }

    }else{
        const DoubleImageWindow * diw = dynamic_cast<const DoubleImageWindow*>(from);
        const Image_t<double> *image = diw->getImage();
        for(int k=0;k<image->getNbChannels();k++){
            double min; min = image->min(k); mintemp = std::min(mintemp,min);
            model->setItem(this->MIN,k,new QStandardItem(QString("%1").arg(image->min(k))));
            model->setItem(this->MEAN,k,new QStandardItem(QString("%1").arg(image->mean(k))));
            double max; max = image->max(k); maxtemp = std::max(max,maxtemp);
            model->setItem(this->MAX,k,new QStandardItem(QString("%1").arg(max)));
            model->setItem(this->STDDEV,k,new QStandardItem(QString("%1").arg(image->deviation((unsigned int)(k)))));
        }
    }

    _max = maxtemp;
    _min = mintemp;
    _maxabs = std::max(std::abs(_max),std::abs(_min));
    ui->tableViewInfo->setModel(model);
    ui->tableViewInfo->resizeColumnsToContents();
}

ParamRep * ApplyOpDialog::getParam(){

    /*
     *enum Param{START, OPERATION, VALROUND, VALMIN, VALMAX, VALCENTER, VALBEFCENTER, CUTUP, CUTDOWN, END};
        enum StandardOp{STANDARDCUT,STANDARDABS,STANDARDNORM, STANDARDROUND};
        enum ValRound{ROUND, FLOOR, CEIL, TRUNC};
     */
    int operation, valrou, start=0, end=0;
    double valmi, valma, valc, valb, valup, vald;
    for(int ind = ParamRep::START;ind < ParamRep::END;ind++){
        switch(ind){
            case ParamRep::START        :  ;break;
            case ParamRep::OPERATION    :  operation= getOp();break;
            case ParamRep::VALROUND     :  valrou= getRound();break;
            case ParamRep::VALMIN       :  valmi= ui->doubleSpinBoxLow->value();break;
            case ParamRep::VALMAX       :  valma= ui->doubleSpinBoxUp->value();break;
            case ParamRep::VALCENTER    :  valc= ui->doubleSpinBoxCenter->value();break;
            case ParamRep::VALBEFCENTER :  valb= ui->doubleSpinBoxBefCenter->value();break;
            case ParamRep::CUTUP        :  valup= ui->spinBoxCutUp->value();break;
            case ParamRep::CUTDOWN      :  vald= ui->spinBoxCutDown->value();break;
            case ParamRep::END          :  ;break;
        }
    }
    ParameterRep newparameter = {start,operation,valrou,valmi,valma,valc,valb,valup,vald};
    ParamRep *param = new ParamRep(newparameter);

    return param;

}

ParamRep::StandardOp ApplyOpDialog::getOp(){
    ParamRep::StandardOp op;
    if(ui->radioButtonAbs->isChecked()){
        op = ParamRep::STANDARDABS;
    }else if(ui->radioButtonClipping->isChecked()){
        op = ParamRep::STANDARDCUT;
    }else if(ui->radioButtonRound->isChecked()){
        op = ParamRep::STANDARDROUND;
    }else if(ui->radioButtonStretch->isChecked()){
        op = ParamRep::STANDARDNORM;
    }
    return op;
}

ParamRep::ValRound ApplyOpDialog::getRound(){
    ParamRep::ValRound type;
    if(ui->radioButtonOpCeil->isChecked()){
        type = ParamRep::CEIL;
    }else if(ui->radioButtonOpFloor->isChecked()){
        type = ParamRep::FLOOR;
    }else if(ui->radioButtonOpRound->isChecked()){
        type = ParamRep::ROUND;
    }else if(ui->radioButtonOpTrunc->isChecked()){
        type = ParamRep::TRUNC;
    }
    return type;
}

void ApplyOpDialog::CheckCut(){
    QDoubleSpinBox* spintemp = static_cast<QDoubleSpinBox*>(QObject::sender()) ;
    if(ui->spinBoxCutDown == spintemp && spintemp->value() >= ui->spinBoxCutUp->value())
        spintemp->setValue(ui->spinBoxCutUp->value()-1);
    if(ui->spinBoxCutUp == spintemp && spintemp->value() <= ui->spinBoxCutDown->value())
        spintemp->setValue(ui->spinBoxCutDown->value()+1);
}

void ApplyOpDialog::CheckStretch(){//case free
    QDoubleSpinBox* spintemp = static_cast<QDoubleSpinBox*>(QObject::sender()) ;

    //We check the values are correct
    if( ui->doubleSpinBoxLow == spintemp && spintemp->value() >= ui->doubleSpinBoxCenter->value()){
        ui->doubleSpinBoxLow->setValue(ui->doubleSpinBoxCenter->value()-1);
    }
    else
    if(ui->doubleSpinBoxUp == spintemp && spintemp->value() <= ui->doubleSpinBoxCenter->value()){
        ui->doubleSpinBoxCenter->setValue(ui->doubleSpinBoxCenter->value()+1);
    }
    else
    if(ui->doubleSpinBoxCenter == spintemp){
        if(spintemp->value() >= ui->doubleSpinBoxUp->value()){
            spintemp->setValue(ui->doubleSpinBoxUp->value()-1);
        }else if(spintemp->value() <= ui->doubleSpinBoxLow->value()){
            spintemp->setValue(ui->doubleSpinBoxLow->value()+1);
        }
    }
    else
    if(ui->doubleSpinBoxBefCenter == spintemp){
        if(spintemp->value() >= _max){
            spintemp->setValue(_max-0.1);
        }else if(spintemp->value() <= _min){
            spintemp->setValue(_min+0.1);
        }
    }


    /*We apply the policies
     */

    //Policy default
    if(ui->radioButtonDefault->isChecked()){
        //void
    }

    if(ui->radioButtonLinear->isChecked()){//Policy Linear

        if(ui->doubleSpinBoxLow == spintemp || ui->doubleSpinBoxCenter == spintemp){
            int size = (ui->doubleSpinBoxCenter->value() - ui->doubleSpinBoxLow->value());
            ui->doubleSpinBoxUp->setValue(ui->doubleSpinBoxCenter->value()+size);
        }
        getBefCenter();
    }

}

void ApplyOpDialog::ManageButton(){
    QRadioButton * radiotemp = static_cast<QRadioButton*>(QObject::sender()) ;
    if(ui->radioButtonDefault == radiotemp){
        ui->doubleSpinBoxBefCenter->setEnabled(false);
        ui->doubleSpinBoxLow->setEnabled(false);
        ui->doubleSpinBoxCenter->setEnabled(false);
        ui->doubleSpinBoxUp->setEnabled(false);

        ui->doubleSpinBoxLow->setValue(0.);
        ui->doubleSpinBoxCenter->setValue(127.5);
        ui->doubleSpinBoxUp->setValue(255.);
        getBefCenter();

    }else if(ui->radioButtonLinear == radiotemp){
        ui->doubleSpinBoxBefCenter->setEnabled(false);
        ui->doubleSpinBoxLow->setEnabled(true);
        ui->doubleSpinBoxCenter->setEnabled(true);
        ui->doubleSpinBoxUp->setEnabled(false);

        ui->doubleSpinBoxLow->setValue(0.);
        ui->doubleSpinBoxCenter->setValue(127.5);
        ui->doubleSpinBoxUp->setValue(255.);
        getBefCenter();

    }else if(ui->radioButtonFree == radiotemp){
        ui->doubleSpinBoxBefCenter->setEnabled(true);
        ui->doubleSpinBoxLow->setEnabled(true);
        ui->doubleSpinBoxCenter->setEnabled(true);
        ui->doubleSpinBoxUp->setEnabled(true);

        ui->doubleSpinBoxLow->setValue(0.);
        ui->doubleSpinBoxCenter->setValue(127.5);
        ui->doubleSpinBoxUp->setValue(255.);
        getBefCenter();

    }
}

void ApplyOpDialog::getBefCenter(){
    double valbef;
    double cent = ui->doubleSpinBoxCenter->value();
    double width = cent - ui->doubleSpinBoxLow->value();
    double max = _maxabs;
    //algo  befval = max(cent-width)/cent
    //valbef = (_maxabs*cent -  _maxabs*(cent-ui->doubleSpinBoxLow->value()))/cent;
    valbef = max * (cent - width) / cent;
    if(valbef >= _max){
        valbef = _max-0.1;
    }else if(valbef <= _min){
        valbef = _min+0.1;
    }
    ui->doubleSpinBoxBefCenter->setValue(valbef);
}


















